package com.share.config.email;

import com.alibaba.fastjson.JSON;
import com.share.common.utils.FileUtil;
import com.share.common.utils.PinYinUtil;
import com.share.config.email.template.AbstractTempleate;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Component;

import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeUtility;
import javax.mail.search.*;
import java.io.File;
import java.io.InputStream;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;

@Slf4j
@Component
public class EmailUtil {
    @Autowired
    private EmailProperties emailProperties;
    @Autowired
    JavaMailSender javaMailSender;

    //发送邮件
    public void sendEmail(AbstractTempleate template) {
        try {
            MimeMessage mimeMessage = javaMailSender.createMimeMessage();
            MimeMessageHelper helper = new MimeMessageHelper(mimeMessage);
            helper.setFrom(template.get_mailFrom());
            helper.setTo(template.get_users());
            helper.setSubject(template.get_subject());
            helper.setText(template.build(), true);
            javaMailSender.send(mimeMessage);
        } catch (Exception e) {
            log.error("邮件发送失败template={}", JSON.toJSON(template), e);
        }
    }

    //接收邮件---邮件服务间只能收最近30的,这是极限
    //
    //pop3：
    // 1.用户的客户端所做的任何操作都是不会反馈到服务器上的
    // 2.POP3协议无法获取邮件状态(已读或未读)
    // 3.支持各种字段检索
    //
    //IAMP:
    // 0.邮件获取响应迅速快,pop3比较迟钝
    // 1.用户在客户端的操作可以实时的反馈到服务器上
    // 2.IMAP还可以指定下载邮件的某些内容
    // 3.不支持中文件检索,且支持subject,sendUser,bodyStr的英文检索,如果是中文则查询不到内容
    public List<EMessage> listEmail(String subject, String sendUserEmail, String bodyStr, Date sendStartDateTime, Date sendEndDateTime) {
        List<EMessage> reList = new LinkedList<>();

        //创建属性对象
        Properties props = new Properties();
        props.put("mail.store.protocol", emailProperties.getStoreProtocol());
        final boolean IS_IMAP = "imap".equals(emailProperties.getStoreProtocol()) ? true : false;
        Folder folder = null;
        try {
            //创建会话
            Session session = Session.getDefaultInstance(props, null);
            //存储对象
            Store store = session.getStore(emailProperties.getStoreProtocol());
            //连接
            store.connect(emailProperties.getHost(), emailProperties.getUsername(), emailProperties.getPassword());
            //创建目录对象
            folder = store.getFolder("inbox");
            if (folder != null) {
                folder.open(Folder.READ_ONLY);
            }

            //设置过滤条件
            SearchTerm[] searchTerms = pkgMessageFilter(IS_IMAP, subject, sendUserEmail, bodyStr, sendStartDateTime, sendEndDateTime);

            Message[] tmpMessages = null;
            if (searchTerms != null && searchTerms.length > 0) {
                tmpMessages = folder.search(new AndTerm(searchTerms));
            } else {
                tmpMessages = folder.getMessages();
            }

            //数据提取
            if (tmpMessages != null || tmpMessages.length > 0) {
                int len = tmpMessages.length;
                for (int i = 0; i < len; i++) {
                    EMessage record = convertMessage(tmpMessages[i], IS_IMAP, subject, sendUserEmail, bodyStr, sendStartDateTime, sendEndDateTime);
                    if (record == null) {
                        continue;
                    }

                    reList.add(record);
                }
                log.info("拉取到邮件数={},按条件过滤后邮件数={}", tmpMessages.length, reList.size());
            }
        } catch (Exception e) {
            log.error("拉取到邮件异常", e);
        } finally {
            if (folder != null) {
                try {
                    folder.close();
                } catch (MessagingException e) {
                    log.error("拉取到邮件异常---关闭文件夹异常", e);
                }
            }
        }
        return reList;
    }

    //条件拼接
    private SearchTerm[] pkgMessageFilter(boolean IS_IMAP, String subject, String sendUserEmail, String bodyStr, Date sendStartDateTime, Date sendEndDateTime) {
        SearchTerm[] searchTerms = null;

        //设置过滤条件
        List<SearchTerm> list = new LinkedList();
        if (StringUtils.isNotBlank(subject)) {
            if (IS_IMAP && PinYinUtil.isContainHanZi(subject)) {
                //跳过
            } else {
                list.add(new SubjectTerm(subject)); //主题
            }
        }

        if (StringUtils.isNotBlank(sendUserEmail)) {
            list.add(new FromStringTerm(sendUserEmail)); //发件人中文名
        }

        if (StringUtils.isNotBlank(bodyStr)) {
            if (IS_IMAP && PinYinUtil.isContainHanZi(bodyStr)) {
                //跳过
            } else {
                list.add(new BodyTerm(bodyStr)); //邮件正文包含
            }
        }

        if (sendStartDateTime != null) {
            list.add(new SentDateTerm(ComparisonTerm.GE, sendStartDateTime));   //ge=6 #表示大于等于的邮件
        }

        if (sendEndDateTime != null) {
            list.add(new SentDateTerm(ComparisonTerm.LE, sendEndDateTime));   //le=1 #表示大小于等于的邮件
        }

        if (list.size() > 0) {
            searchTerms = list.toArray(new SearchTerm[list.size()]);
        }
        return searchTerms;
    }

    //内容转换与过滤
    private EMessage convertMessage(Message tmpMessage, boolean IS_IMAP, String subject, String sendUserEmail, String bodyStr, Date sendStartDateTime, Date sendEndDateTime) {
        EMessage record = new EMessage();
        MimeMessage msg = (MimeMessage) tmpMessage;
        try {
            //主题赛选
            record.setSubjec(msg.getSubject());
            if (IS_IMAP) { //结果赛选
                if (StringUtils.isNotBlank(subject) && StringUtils.isNotBlank(record.getSubjec())) {
                    if (!record.getSubjec().contains(subject)) {
                        return null;
                    }
                }
            }

            //发送时间赛选
            record.setSentDate(msg.getSentDate());
            if (IS_IMAP) {//时间赛选
                if (record.getSentDate() != null) {
                    long sendTime = record.getSentDate().getTime();
                    if (sendStartDateTime != null && sendStartDateTime.getTime() > sendTime) {
                        return null;
                    }

                    if (sendEndDateTime != null && sendEndDateTime.getTime() < sendTime) {
                        return null;
                    }
                }
            }

            //邮件内容
            Part part = (Part) tmpMessage;
            String result = getMailTextContent(part);
            result = StringUtils.isBlank(result) ? null : result;
            record.setContent(result);
            if (IS_IMAP) { //bodyStr赛选
                if (StringUtils.isNotBlank(bodyStr) && StringUtils.isNotBlank(record.getContent())) {
                    if (!record.getContent().contains(bodyStr)) {
                        return null;
                    }
                }
            }

            //邮件类型
            String tmpContentType = msg.getContentType();
            String[] split = tmpContentType.split(";");
            record.setContentType(split[0]);

            //发送人的处理
            String fromUser = getAddresss(msg.getFrom());
            record.setFromUser(fromUser);

            //收件人-抄送-密送
            String toUser = getAddresss(msg.getRecipients(Message.RecipientType.TO));
            String ccUser = getAddresss(msg.getRecipients(Message.RecipientType.CC));
            String bccUser = getAddresss(msg.getRecipients(Message.RecipientType.BCC));
            record.setToUser(toUser);
            record.setCcUser(ccUser);
            record.setBccUser(bccUser);
        } catch (Exception e1) {
            e1.printStackTrace();
            record = null;
        }
        return record;
    }

    //读取邮件自身的文本内容
    //https://blog.51cto.com/u_16099240/7222999
    private static String getMailTextContent(Part part) throws Exception {
        String result = "";
        //如果是文本类型的附件，通过getContent方法可以取到文本内容，但这不是我们需要的结果，所以在这里要做判断
        boolean isContainTextAttach = part.getContentType().indexOf("name") > 0;
        if (part.isMimeType("text/*") && !isContainTextAttach) {
            result = part.getContent().toString();
        } else if (part.isMimeType("message/rfc822")) {
            result += getMailTextContent((Part) part.getContent());
        } else if (part.isMimeType("multipart/*")) {
            Multipart multipart = (Multipart) part.getContent();
            int partCount = multipart.getCount();
            for (int i = 0; i < partCount; i++) {
                BodyPart bodyPart = multipart.getBodyPart(i);
                result += getMailTextContent(bodyPart);
            }
        }
        return result;
    }

    /**
     * 保存附件
     *
     * @param part
     * @param destDir
     * @return
     * @throws Exception
     */
    private static boolean saveAttachment(Part part, String destDir) throws Exception {
        boolean res = false;
        if (part.isMimeType("multipart/*")) {
            Multipart multipart = (Multipart) part.getContent();    //复杂体邮件
            //复杂体邮件包含多个邮件体
            int partCount = multipart.getCount();
            for (int i = 0; i < partCount; i++) {
                //获得复杂体邮件中其中一个邮件体
                BodyPart bodyPart = multipart.getBodyPart(i);
                //某一个邮件体也有可能是由多个邮件体组成的复杂体
                String disp = bodyPart.getDisposition();
                if (disp != null && (disp.equalsIgnoreCase(Part.ATTACHMENT) || disp.equalsIgnoreCase(Part.INLINE))) {
                    String fileName = bodyPart.getFileName();
                    fileName = StringUtils.isBlank(fileName) ? "" : MimeUtility.decodeText(fileName);
                    InputStream is = bodyPart.getInputStream();

                    //保存文件
                    byte[] bytes = FileUtil.readByte(is);
                    FileUtil.writeByte(destDir + File.separator + fileName, bytes);

                    res = true;
                } else if (bodyPart.isMimeType("multipart/*")) {
                    saveAttachment(bodyPart, destDir);
                    res = true;
                } else {
                    String contentType = bodyPart.getContentType();
                    String fileName = bodyPart.getFileName();
                    fileName = StringUtils.isBlank(fileName) ? "" : MimeUtility.decodeText(fileName);
                    if (contentType.indexOf("name") != -1 || contentType.indexOf("application") != -1) {
                        byte[] bytes = FileUtil.readByte(bodyPart.getInputStream());
                        FileUtil.writeByte(destDir + File.separator + fileName, bytes);
                        res = true;
                    }
                }
            }
        } else if (part.isMimeType("message/rfc822")) {
            saveAttachment((Part) part.getContent(), destDir);
        }
        return res;
    }

    //解析或者获取地址,按照kv格式分割
    private static String getAddresss(Address[] addresses) {
        if (addresses == null || addresses.length == 0) {
            return null;
        }
        StringBuffer sb = new StringBuffer();
        int len = addresses.length;
        for (int i = 0; i < len; i++) {
            InternetAddress tmpAddress = (InternetAddress) addresses[i];
            String personal = tmpAddress.getPersonal();
            personal = StringUtils.isBlank(personal) ? "" : personal;
            String address = tmpAddress.getAddress();
            address = StringUtils.isBlank(address) ? "" : address;
            sb.append(String.format("&%s=%s", personal, address));
        }

        if (sb.length() > 0) {
            sb.deleteCharAt(0);
        }

        return sb.toString();
    }

}

